#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>

#define die(str, args...) do {			\
    perror(str);				\
    exit(EXIT_FAILURE);				\
  } while(0)


class virtualJoystick
{
private:
  
  int                    fd;
  struct uinput_user_dev uidev;
    
public:
  
  struct input_event     ev;

  ~virtualJoystick() 
  { 
    if(ioctl(fd, UI_DEV_DESTROY) < 0)
      die("error: ioctl");
  }

  virtualJoystick()
  {
    fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK);
    if(fd < 0)
      die("error: open");
    
    memset(&uidev, 0, sizeof(uidev));
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "easyTrack");
    uidev.id.version = 4; 
    uidev.id.bustype = BUS_USB; 
    uidev.id.vendor = 0x00046d; // Logitech 
    uidev.id.product = 0; 
    
    ioctl (fd, UI_SET_EVBIT, EV_SYN); 
    ioctl (fd, UI_SET_EVBIT, EV_ABS); 
    ioctl (fd, UI_SET_EVBIT, EV_KEY); 
    
    ioctl (fd, UI_SET_ABSBIT, ABS_X); 
    ioctl (fd, UI_SET_ABSBIT, ABS_Y); 
    ioctl (fd, UI_SET_ABSBIT, ABS_Z); 
    ioctl (fd, UI_SET_ABSBIT, ABS_WHEEL); 
    ioctl (fd, UI_SET_ABSBIT, ABS_GAS); 

    ioctl (fd, UI_SET_KEYBIT, BTN_TOP); 
    ioctl (fd, UI_SET_KEYBIT, BTN_TOP2); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE2); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE3); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE4); 
    
    for(int i = 0; i < ABS_MAX;++i) 
      { 
	uidev.absmax[i] = 511; 
	uidev.absmin[i] = -512; 
      } 
//     // The jogwheel is different 
//     uidev.absmax[ABS_Z] = 2047; 
//     uidev.absmin[ABS_Z] =-2048; 
//     // .. and rudder as well 
//     uidev.absmax[ABS_RUDDER] = 255; 
//     uidev.absmin[ABS_RUDDER] =-256;
    
    // Create device 
    if ( write (fd, &uidev, sizeof (uidev) ) <0)
      {
	fprintf (stderr,"Unable to create UIDEVUT device. Are you root?\n");  
      }
    
    if (ioctl (fd, UI_DEV_CREATE)) 
	{ 
	  fprintf (stderr,"Unable to init UIDEVUT device.\n"); 
	  exit(EXIT_FAILURE); 
	  //return (-1)
	} 
      //return (0);
  }
  
  void sendCommand ()
  {
    if(write(fd, &ev, sizeof(struct input_event)) < 0)
      die("error: write");	      
  }
  
  void sendAll (int X, int Y, int Z, int WHEEL, int GAS)
  {
    memset(&ev, 0, sizeof(struct input_event)); 
    ev.type = EV_ABS; 
    ev.code = ABS_X; 
    ev.value = X; 
 
    memset(&ev, 0, sizeof(struct input_event)); 
    ev.type = EV_ABS; 
    ev.code = ABS_Y; 
    ev.value = Y; 

    memset(&ev, 0, sizeof(struct input_event)); 
    ev.type = EV_ABS; 
    ev.code = ABS_Z; 
    ev.value = Z; 
    
    memset(&ev, 0, sizeof(struct input_event)); 
    ev.type = EV_ABS; 
    ev.code = ABS_WHEEL; 
    ev.value = WHEEL; 
    
    memset(&ev, 0, sizeof(struct input_event)); 
    ev.type = EV_ABS; 
    ev.code = ABS_GAS; 
    ev.value = GAS; 

  }
  
};


   int main(void)
   {
     virtualJoystick* js0 = new (virtualJoystick);

     for (int i = 0; i < 100 ; i++)
       {
 	js0->sendAll(1*i,2*i,3*i,4*i,5*i);
 	sleep (1);
       }

     delete (js0);    
   }
